package com.iims.flowable.factory;

import cn.hutool.core.util.StrUtil;
import cn.hutool.db.sql.Direction;
import cn.hutool.db.sql.Order;
import com.iims.common.constant.HttpStatus;
import com.iims.common.core.page.PageDomain;
import com.iims.common.core.page.TableDataInfo;
import com.iims.common.core.page.TableSupport;
import com.iims.common.utils.StringUtils;
import com.iims.common.utils.spring.SpringUtils;
import com.iims.flowable.common.constant.FlowableConstant;
import com.iims.flowable.flow.vo.ExecuteTaskDataVo;
import com.iims.flowable.flow.vo.request.IBaseQueryVo;
import com.iims.flowable.flow.vo.wrapper.IListFlowWrapper;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.ValuedDataObject;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.api.query.Query;
import org.flowable.common.engine.api.query.QueryProperty;
import org.springframework.http.MediaType;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class BaseFlowableController extends BaseFlowResource {


    /**
     * 设置请求分页数据
     */
    protected PageDomain getPageDomain() throws Exception {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
            if (pageNum <= 0 || pageSize == 0) {
                throw new Exception("pageNum[1,maxValue]，pageSize(0,maxValue)请检查参数取值范围！");
            }
            //pageDomain.setOrderByColumn(SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()));
        } else {
            throw new Exception("分页参数缺失，请检查接口！");
        }
        return pageDomain;
    }

    protected List listWrapper(Class<? extends IListFlowWrapper> listWrapperClass, List list) {
        IListFlowWrapper listWrapper = SpringUtils.getBean(listWrapperClass);
        List result = listWrapper.execute(list);
        return result;
    }

    /**
     * 分页查询数据
     *
     * @param baseQueryVo           查询视图
     * @param query                 查询query
     * @param listWrapperClass      数据包装类
     * @param allowedSortProperties 允许排序字段
     * @return
     */
    protected TableDataInfo pageList(IBaseQueryVo baseQueryVo,
                                     Query query,
                                     Class<? extends IListFlowWrapper> listWrapperClass,
                                     Map<String, QueryProperty> allowedSortProperties) {
        return pageList(baseQueryVo, query, listWrapperClass, allowedSortProperties, null);

    }

    /**
     * 分页查询数据
     *
     * @param baseQueryVo             查询视图
     * @param query                   查询query
     * @param listWrapperClass        数据包装类
     * @param allowedSortProperties   允许排序字段
     * @param defaultDescSortProperty 默认排序字段
     * @return
     */
    protected TableDataInfo pageList(IBaseQueryVo baseQueryVo,
                                     Query query,
                                     Class<? extends IListFlowWrapper> listWrapperClass,
                                     Map<String, QueryProperty> allowedSortProperties,
                                     QueryProperty defaultDescSortProperty) {
        PageDomain pageDomain = baseQueryVo.selectPageDomain();
        baseQueryVo.genSearchQuery(query);

        List list = null;
        if (pageDomain == null) {
            list = query.list();
            pageDomain.setPageNum(0);
            pageDomain.setPageSize(0);
        } else {
            List<Order> orderList = null;
            if (StringUtils.isNotEmpty(pageDomain.getOrderByColumn())
                    && StringUtils.isNotEmpty(pageDomain.getIsAsc())) {
                Order order = new Order();
                order.setField(pageDomain.getOrderByColumn());
                order.setDirection(Direction.fromString(pageDomain.getIsAsc()));
                orderList = Arrays.asList(order);
            }
            setQueryOrder(orderList, query, allowedSortProperties, defaultDescSortProperty);
            list = query.listPage((int) pageDomain.getPageNum() - 1, pageDomain.getPageSize());
        }
        if (listWrapperClass != null) {
            IListFlowWrapper listWrapper = SpringUtils.getBean(listWrapperClass);
            list = listWrapper.execute(list);
        }

        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setTotal(query.count());
        rspData.setRows(list);
        rspData.setPageDomain(pageDomain);
        return rspData;
    }

    protected void setQueryOrder(List<Order> orders, Query query, Map<String, QueryProperty> properties,
                                 QueryProperty defaultDescSortProperty) {
        boolean orderByDefaultDescSortProperty =
                (orders == null || orders.size() == 0 || properties.isEmpty()) && defaultDescSortProperty != null;
        if (orderByDefaultDescSortProperty) {
            query.orderBy(defaultDescSortProperty).desc();
        } else {
            if (orders != null && orders.size() > 0) {
                for (Order order : orders) {
                    QueryProperty qp = properties.get(order.getField());
                    if (qp == null) {
                        throw new FlowableIllegalArgumentException("Value for param 'orders' is not valid, '" + order.getField() + "' is not a valid property");
                    }
                    query.orderBy(qp);
                    if (order.getDirection() == Direction.ASC) {
                        query.asc();
                    } else {
                        query.desc();
                    }
                }
            }
        }
    }

    /**
     * 发送图片流
     */
    @Deprecated
    protected void sendImageStream(HttpServletResponse response, InputStream in) {
        OutputStream os = null;
        BufferedImage image = null;
        try {
            image = ImageIO.read(in);
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
            os = response.getOutputStream();

            if (image != null) {
                ImageIO.write(image, "png", os);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 是否显示业务key
     *
     * @param processDefinitionId
     * @return
     */
    protected boolean isShowBusinessKey(String processDefinitionId) {
        Process process = repositoryService.getBpmnModel(processDefinitionId).getMainProcess();
        Map<String, List<ExtensionElement>> extensionElements = process.getExtensionElements();
        if (extensionElements != null && !extensionElements.isEmpty() && extensionElements.get("properties") != null && extensionElements.get("properties").size() > 0) {
            List<ExtensionElement> properties = extensionElements.get("properties");
            for (ExtensionElement extensionElement : properties) {
                List<ExtensionElement> property = extensionElement.getChildElements().get("property");
                if (property != null && property.size() > 0) {
                    for (ExtensionElement propertyElement : property) {
                        String name = propertyElement.getAttributeValue(null, "name");
                        String value = propertyElement.getAttributeValue(null, "value");
                        if ("showBusinessKey".equals(name)) {
                            if (Boolean.valueOf(value)) {
                                return true;
                            } else {
                                return false;
                            }
                        }
                    }
                }
            }
        }

        List<ValuedDataObject> dataObjects =
                repositoryService.getBpmnModel(processDefinitionId).getMainProcess().getDataObjects();
        if (dataObjects != null && dataObjects.size() > 0) {
            for (ValuedDataObject valuedDataObject : dataObjects) {
                if ("showBusinessKey".equals(valuedDataObject.getId())) {
                    if (valuedDataObject.getValue() instanceof String) {
                        return Boolean.valueOf((String) valuedDataObject.getValue());
                    } else if (valuedDataObject.getValue() instanceof Boolean) {
                        return (Boolean) valuedDataObject.getValue();
                    } else {
                        return false;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取起始任务数据表单
     *
     * @param processDefinitionId
     * @param processDefinitionKey
     * @param processInstanceId
     * @param businessKey
     * @return
     */
    public void initStartDataFormBack(String processDefinitionId, String processDefinitionKey,
                                      String processInstanceId, String businessKey,
                                      ExecuteTaskDataVo executeTaskDataVo) {
        //1.获取起始表单
        String startFormKey = formService.getStartFormKey(processDefinitionId);
        //1.1若起始表单不为空 返回存储的起始表单数据
        if (StrUtil.isNotBlank(startFormKey)) {
            Object renderedStartForm = cmisTaskFormService.getRenderedTaskFormBack(processInstanceId, startFormKey);
            executeTaskDataVo.setStartFormKey(startFormKey);
            executeTaskDataVo.setRenderedStartForm(renderedStartForm);
        } else {
            //1.2起始数据不为空，返回基础业务数据，若为空则返回自定义任务起始表单数据
            Object renderedStartForm = flowBusinessUtils.getBusinessObj(processDefinitionKey, businessKey);
            if (null == renderedStartForm) {
                renderedStartForm = cmisTaskFormService.getRenderedStartTaskFormBack(processDefinitionId);
                executeTaskDataVo.setStartFormKey(FlowableConstant.PROCESS_INSTANCE_FORM_DATA);
                executeTaskDataVo.setRenderedStartForm(renderedStartForm);
            } else {
                executeTaskDataVo.setBusinessData(renderedStartForm);
            }

        }
    }
}